// .cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "VelocityParticle.h"
#include <osgViewer/Viewer>
#include <osgEarth/Notify>
#include <osgEarthUtil/EarthManipulator>
#include <osgEarth/MapNode>
#include <osgEarth/ImageLayer>
#include <osgEarth/ElevationLayer>
#include <osgEarth/ShaderGenerator>
#include <osgEarthDrivers/gdal/GDALOptions>
#include <osgEarthDrivers/tms/TMSOptions>
#include <osgDB/ReadFile>
#include <osgGA/TrackballManipulator>
#include <osgUtil/Optimizer>
#include <iostream>
//#include <osgEarth/Metrics>
#include <cassert>
#include <osg/LineWidth>
#include <osg/BlendFunc>
#include <osgEarthUtil/TMS>
#include <osgDB/WriteFile>
//#include <osg/BillBoard>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <png.h>

using namespace osgEarth;
using namespace osgEarth::Util;
#include <string>
#include <iostream>
using namespace std;

osg::ref_ptr<osg::Image> g_fboImage;
int g_fboImageWidth = -1;
int g_fboImageHeight = -1;

class MyPostDrawCallBack : public osg::Camera::DrawCallback
{
public:
    virtual void operator()(osg::RenderInfo &renderInfo) const;

private:
};

void MyPostDrawCallBack::operator()(osg::RenderInfo &renderInfo) const
{
    // from https://osg-users.openscenegraph.narkive.com/XtKczA0e/read-frame-buffer-back-into-main-memory
    osg::GraphicsContext *gc = renderInfo.getState()->getGraphicsContext();
    int width = gc->getTraits()->width;
    int height = gc->getTraits()->height;
    if (width != g_fboImageWidth || height != g_fboImageHeight)
    {
        g_fboImage = new osg::Image;
        g_fboImageWidth = width;
        g_fboImageHeight = height;
    }
    g_fboImage->readPixels(0, 0, gc->getTraits()->width, gc->getTraits()->height, GL_RGB, GL_UNSIGNED_BYTE);
    bool retValBmp = osgDB::writeImageFile(*g_fboImage, "testframebuffer.bmp");
    int kkk = 0;
}

int main()
{
    cout << "version v3.0 3d wind. 2023-10-21." << endl;
    cout << "v3.0.1 no wind data, just git the codes in hp." << endl; // 2024/6/20

    // load wind data
    //osgEarth::initialize();
    // create a viewer
    osgViewer::Viewer viewer;
    viewer.setUpViewInWindow(0, 100, 800, 600);
    // ? why
    viewer.setReleaseContextAtEndOfFrameHint(false);
    // set camera manipulator
    viewer.setCameraManipulator(new EarthManipulator);
    // viewer.setCameraManipulator(new osgGA::TrackballManipulator);
    // viewer.getCamera()->setClearMask(GL_DEPTH_BUFFER_BIT);
   viewer.getCamera()->setPostDrawCallback(new MyPostDrawCallBack);
    {
        // camera quad
        float zval = -100;
        osg::Geometry *cameraQuad = osg::createTexturedQuadGeometry(osg::Vec3(0, 0, zval),
                                                                    osg::Vec3(800, 0, zval),
                                                                    osg::Vec3(0, 600, zval),
                                                                    1,
                                                                    1);
        osg::Vec4Array *colors = new osg::Vec4Array;
        osg::Vec4 colorOne(0, 0, 0.5, 1);
        colors->push_back(colorOne);
        cameraQuad->setColorArray(colors, osg::Array::Binding::BIND_OVERALL);
        osg::Billboard *billborad = new osg::Billboard;
        billborad->setMode(osg::Billboard::Mode::POINT_ROT_EYE);
        billborad->addDrawable(cameraQuad);
        viewer.getCamera()->addChild(billborad);
    }

    osg::Group *root = new osg::Group;

    // Map is datamodel for collection of layers.
    osg::ref_ptr<osgEarth::Map> map = new osgEarth::Map;
    // GeoTiff Layer
	osgEarth::Drivers::GDALOptions gdal;
	gdal.url() = "data/world.tif";
	osg::ref_ptr<osgEarth::ImageLayer> layer = new osgEarth::ImageLayer("BlueMarble", gdal);
    map->addImageLayer(layer);
    //map->addLayer(layer);
    // Elevation Layer
    //osg::ref_ptr<TMSElevationLayer> elevLayer = new TMSElevationLayer();
    //elevLayer->setURL(osgEarth::URI("http://readymap.org/readymap/tiles/1.0.0/116/"));
    //map->addLayer(elevLayer);

    osgEarth::Drivers::TMSOptions tms0;
	tms0.url() = "http://readymap.org/readymap/tiles/1.0.0/7/";
	osg::ref_ptr<osgEarth::ImageLayer> imglayer = new osgEarth::ImageLayer("ReadyMap.org - Imagery", tms0);
    map->addImageLayer(imglayer);
    //map->addLayer(imglayer);

	osgEarth::Drivers::TMSOptions tms;
	tms.url() = "http://readymap.org/readymap/tiles/1.0.0/9/";
	osg::ref_ptr<osgEarth::ElevationLayer> elelayer = new osgEarth::ElevationLayer("ReadyMap.org - Elevation", tms);
    map->addElevationLayer(elelayer);
    //map->addLayer(elelayer);

    // MapNode is the render or visualization of Map.
    osg::ref_ptr<osgEarth::MapNode> mapNode = new osgEarth::MapNode(map.get());
    root->addChild(mapNode);

    // background truecolor imagery for
    if (false)
    {
        osg::Geometry *backQuad = new osg::Geometry;
        backQuad->setUseVertexBufferObjects(true);
        osg::Vec3Array *vertices = new osg::Vec3Array;
        osg::Vec2Array *texCoors = new osg::Vec2Array;
        vertices->push_back(osg::Vec3(0, 0.1, 0));
        vertices->push_back(osg::Vec3(360, 0.1, 0));
        vertices->push_back(osg::Vec3(360, 0.1, 180));
        vertices->push_back(osg::Vec3(0, 0.1, 180));

        texCoors->push_back(osg::Vec2(0, 0));
        texCoors->push_back(osg::Vec2(1, 0));
        texCoors->push_back(osg::Vec2(1, 1));
        texCoors->push_back(osg::Vec2(0, 1));
        backQuad->setVertexArray(vertices);
        backQuad->setTexCoordArray(0, texCoors, osg::Array::BIND_PER_VERTEX);

        osg::Vec4Array *colors = new osg::Vec4Array;
        colors->push_back(osg::Vec4(0.8, 0.8, 0.8, 1));
        backQuad->setColorArray(colors, osg::Array::BIND_OVERALL);

        string backImageName = "data/merge-2023-10-14.jpg";
        // string backImageName = "data/world.png";
        osg::Image *backImg = osgDB::readImageFile(backImageName);
        osg::Texture2D *tex2d = new osg::Texture2D(backImg);
        backQuad->getOrCreateStateSet()->setTextureAttributeAndModes(0, tex2d);
        tex2d->setUnRefImageDataAfterApply(true); // auto release image in host memory.
        backQuad->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_FAN, 0, 4));
        osg::Geode *backNode = new osg::Geode;
        backNode->addDrawable(backQuad);
        root->addChild(backNode);
    }

    // wind
    {
        VelocityParticle vp;
        root->addChild(vp.Get("data/wind.png"));
    }
    viewer.setSceneData(root);
    if (viewer.getCamera()->getViewMatrix().isNaN())
    {
        viewer.getCamera()->setViewMatrix(osg::Matrix::identity());
    }
    //return Metrics::run(viewer);
    return viewer.run();
}
